package pers.chao.tool.spring;

import org.slf4j.Logger;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import pers.chao.tool.aspect.AopUtil;
import pers.chao.tool.infrastructure.log.BaseLogFactory;
import pers.chao.tool.math.RandomUtil;

import java.lang.reflect.Method;

/**
 * Description: spring EL表达式解析执行
 *
 * @author W.Chao
 * @date 2020/12/8 23:51
 **/
public final class SpringElUtil {
	// el表达式解析器
	private static final ExpressionParser parser = new SpelExpressionParser();
	// 参数变量解析
	private static final LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
	private static final Logger logger = BaseLogFactory.getLogger(SpringElUtil.class);

	/**
	 * 解析 el 表达式
	 *
	 * @param method        方法
	 * @param arguments     参数值
	 * @param el            表达式
	 * @param clazz         返回结果的类型
	 * @param defaultResult 默认结果
	 * @return 执行el表达式后的结果
	 */
	public static <T> T parseSpringEL(Method method, Object[] arguments, String el, Class<T> clazz, T defaultResult) {
		String[] params = discoverer.getParameterNames(method);
		EvaluationContext context = new StandardEvaluationContext();
		for (int len = 0; len < params.length; len++) {
			context.setVariable(params[len], arguments[len]);
		}
		try {
			String identify = RandomUtil.random8Char();
			logger.info("[{}]Start parse spring EL. {}", identify, el);
			Expression expression = parser.parseExpression(el);
			T value = expression.getValue(context, clazz);
			logger.info("[{}]Parse spring EL result: method: {}, parameters: {}, before: {}, after: {}", identify, method, AopUtil.getMethodArgsMap(params, arguments), el, value);
			return value;
		} catch (Exception e) {
			return defaultResult;
		}
	}

}
